home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-15  |  27.0 KB  |  1,162 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * ui.c: functions that handle the user interface.
  11.  * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
  12.  *    before the machine specific stuff (mch_*) so that we can call the GUI
  13.  *    stuff instead if the GUI is running.
  14.  * 2. Clipboard stuff.
  15.  * 3. Input buffer stuff.
  16.  */
  17.  
  18. #include "vim.h"
  19.  
  20.     void
  21. ui_write(s, len)
  22.     char_u  *s;
  23.     int        len;
  24. {
  25. #ifdef USE_GUI
  26.     if (gui.in_use && !gui.dying)
  27.     {
  28.     gui_write(s, len);
  29.     if (p_wd)
  30.         gui_wait_for_chars(p_wd);
  31.     return;
  32.     }
  33. #endif
  34. #ifndef NO_CONSOLE
  35.     /* Don't output anything in silent mode ("ex -s") */
  36.     if (!silent_mode)
  37.     mch_write(s, len);
  38. #endif
  39. }
  40.  
  41. /*
  42.  * ui_inchar(): low level input funcion.
  43.  * Get a characters from the keyboard.
  44.  * Return the number of characters that are available.
  45.  * If wtime == 0 do not wait for characters.
  46.  * If wtime == -1 wait forever for characters.
  47.  * If wtime > 0 wait wtime milliseconds for a character.
  48.  */
  49.     int
  50. ui_inchar(buf, maxlen, wtime)
  51.     char_u  *buf;
  52.     int        maxlen;
  53.     long    wtime;        /* don't use "time", MIPS cannot handle it */
  54. {
  55. #ifdef USE_GUI
  56.     if (gui.in_use)
  57.     {
  58.     if (!gui_wait_for_chars(wtime))
  59.         return 0;
  60.     return read_from_input_buf(buf, (long)maxlen);
  61.     }
  62. #endif
  63. #ifndef NO_CONSOLE
  64.     return mch_inchar(buf, maxlen, wtime);
  65. #endif
  66. }
  67.  
  68. /*
  69.  * return non-zero if a character is available
  70.  */
  71.     int
  72. ui_char_avail()
  73. {
  74. #ifdef USE_GUI
  75.     if (gui.in_use)
  76.     {
  77.     gui_mch_update();
  78.     return !vim_is_input_buf_empty();
  79.     }
  80. #endif
  81. #ifndef NO_CONSOLE
  82.     return mch_char_avail();
  83. #endif
  84. }
  85.  
  86. /*
  87.  * Delay for the given number of milliseconds.    If ignoreinput is FALSE then we
  88.  * cancel the delay if a key is hit.
  89.  */
  90.     void
  91. ui_delay(msec, ignoreinput)
  92.     long    msec;
  93.     int        ignoreinput;
  94. {
  95. #ifdef USE_GUI
  96.     if (gui.in_use && !ignoreinput)
  97.     gui_wait_for_chars(msec);
  98.     else
  99. #endif
  100.     mch_delay(msec, ignoreinput);
  101. }
  102.  
  103. /*
  104.  * If the machine has job control, use it to suspend the program,
  105.  * otherwise fake it by starting a new shell.
  106.  * When running the GUI iconify the window.
  107.  */
  108.     void
  109. ui_suspend()
  110. {
  111. #ifdef USE_GUI
  112.     if (gui.in_use)
  113.     {
  114.     gui_mch_iconify();
  115.     return;
  116.     }
  117. #endif
  118.     mch_suspend();
  119. }
  120.  
  121. /*
  122.  * When the OS can't really suspend, call this function to start a shell.
  123.  */
  124.     void
  125. suspend_shell()
  126. {
  127.     MSG_PUTS("new shell started\n");
  128.     mch_call_shell(NULL, SHELL_COOKED);
  129.     need_check_timestamps = TRUE;
  130. }
  131.  
  132.     int
  133. ui_can_restore_title()
  134. {
  135. #ifdef USE_GUI
  136.     /*
  137.      * If GUI is (going to be) used, we can always set the window title.
  138.      * Saves a bit of time, because the X11 display server does not need to be
  139.      * contacted.
  140.      */
  141.     if (gui.starting || gui.in_use)
  142.     return TRUE;
  143. #endif
  144.     return mch_can_restore_title();
  145. }
  146.  
  147.     int
  148. ui_can_restore_icon()
  149. {
  150. #ifdef USE_GUI
  151.     /*
  152.      * If GUI is (going to be) used, we can always set the icon name.
  153.      * Saves a bit of time, because the X11 display server does not need to be
  154.      * contacted.
  155.      */
  156.     if (gui.starting || gui.in_use)
  157.     return TRUE;
  158. #endif
  159.     return mch_can_restore_icon();
  160. }
  161.  
  162. /*
  163.  * Try to get the current window size.    Put the result in Rows and Columns.
  164.  * Return OK when size could be determined, FAIL otherwise.
  165.  */
  166.     int
  167. ui_get_winsize()
  168. {
  169.     int        retval;
  170.  
  171. #ifdef USE_GUI
  172.     if (gui.in_use)
  173.     retval = gui_get_winsize();
  174.     else
  175. #endif
  176.     retval = mch_get_winsize();
  177.  
  178.     /* adjust the default for 'lines' and 'columns' */
  179.     if (retval == OK)
  180.     {
  181.     set_number_default("lines", Rows);
  182.     set_number_default("columns", Columns);
  183.     }
  184.     return retval;
  185. }
  186.  
  187. /*
  188.  * Set the size of the window according to Rows and Columns, if possible.
  189.  */
  190.     void
  191. ui_set_winsize()
  192. {
  193. #ifdef USE_GUI
  194.     if (gui.in_use)
  195.     gui_set_winsize(FALSE);
  196.     else
  197. #endif
  198.     mch_set_winsize();
  199. }
  200.  
  201.     void
  202. ui_breakcheck()
  203. {
  204. #ifdef USE_GUI
  205.     if (gui.in_use)
  206.     gui_mch_update();
  207.     else
  208. #endif /* USE_GUI */
  209.     mch_breakcheck();
  210. }
  211.  
  212. /*****************************************************************************
  213.  * Functions for copying and pasting text between applications.
  214.  * This is always included in a GUI version, but may also be included when the
  215.  * clipboard and mouse is available to a terminal version such as xterm.
  216.  * Note: there are some more functions in ops.c that handle selection stuff.
  217.  */
  218.  
  219. #ifdef USE_CLIPBOARD
  220.  
  221. static void clip_invert_area __ARGS((int, int, int, int));
  222. static void clip_yank_non_visual_selection __ARGS((int, int, int, int));
  223. static void clip_get_word_boundaries __ARGS((VimClipboard *, int, int));
  224. static int  clip_get_line_end __ARGS((int));
  225. static void clip_update_non_visual_selection __ARGS((VimClipboard *, int, int,
  226.                             int, int));
  227.  
  228. #define char_class(c)    (c <= ' ' ? ' ' : vim_iswordc(c))
  229.  
  230. /*
  231.  * Selection stuff using Visual mode, for cutting and pasting text to other
  232.  * windows.
  233.  */
  234.  
  235. /*
  236.  * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
  237.  * is included, but the clipboard can not be used, or TRUE if the clipboard can
  238.  * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
  239.  * the GUI starts.
  240.  */
  241.     void
  242. clip_init(can_use)
  243.     int        can_use;
  244. {
  245.     clipboard.available = can_use;
  246.     clipboard.owned = FALSE;
  247.     clipboard.start.lnum = 0;
  248.     clipboard.start.col = 0;
  249.     clipboard.end.lnum = 0;
  250.     clipboard.end.col = 0;
  251.     clipboard.state = SELECT_CLEARED;
  252. }
  253.  
  254. /*
  255.  * Check whether the VIsual area has changed, and if so try to become the owner
  256.  * of the selection, and free any old converted selection we may still have
  257.  * lying around.  If the VIsual mode has ended, make a copy of what was
  258.  * selected so we can still give it to others.    Will probably have to make sure
  259.  * this is called whenever VIsual mode is ended.
  260.  */
  261.     void
  262. clip_update_selection()
  263. {
  264.     FPOS    start, end;
  265.  
  266.     /* If visual mode is only due to a redo command ("."), then ignore it */
  267.     if (!redo_VIsual_busy && VIsual_active)
  268.     {
  269.     if (lt(VIsual, curwin->w_cursor))
  270.     {
  271.         start = VIsual;
  272.         end = curwin->w_cursor;
  273.     }
  274.     else
  275.     {
  276.         start = curwin->w_cursor;
  277.         end = VIsual;
  278.     }
  279.     if (!equal(clipboard.start, start) || !equal(clipboard.end, end)
  280.                         || clipboard.vmode != VIsual_mode)
  281.     {
  282.         clip_clear_selection();
  283.         clipboard.start = start;
  284.         clipboard.end = end;
  285.         clipboard.vmode = VIsual_mode;
  286.         clip_free_selection();
  287.         clip_own_selection();
  288.         clip_mch_set_selection();
  289.     }
  290.     }
  291. }
  292.  
  293.     void
  294. clip_own_selection()
  295. {
  296.     /*
  297.      * Also want to check somehow that we are reading from the keyboard rather
  298.      * than a mapping etc.
  299.      */
  300.     if (!clipboard.owned)
  301.     clipboard.owned = (clip_mch_own_selection() == OK);
  302. }
  303.  
  304.     void
  305. clip_lose_selection()
  306. {
  307.     clip_free_selection();
  308.     clipboard.owned = FALSE;
  309.     clip_clear_selection();
  310.     clip_mch_lose_selection();
  311. }
  312.  
  313.     void
  314. clip_copy_selection()
  315. {
  316.     if (VIsual_active)
  317.     {
  318.     if (vim_strchr(p_guioptions, GO_ASEL) == NULL)
  319.         clip_update_selection();
  320.     clip_free_selection();
  321.     clip_own_selection();
  322.     if (clipboard.owned)
  323.         clip_get_selection();
  324.     clip_mch_set_selection();
  325.     }
  326. }
  327.  
  328.     void
  329. clip_auto_select()
  330. {
  331.     if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
  332.     clip_copy_selection();
  333. }
  334.  
  335.  
  336. #ifdef USE_GUI
  337.  
  338. /*
  339.  * Stuff for general mouse selection, without using Visual mode.
  340.  */
  341.  
  342. static int clip_compare_pos __ARGS((int row1, int col1, int row2, int col2));
  343.  
  344. /*
  345.  * Compare two screen positions ala strcmp()
  346.  */
  347.     static int
  348. clip_compare_pos(row1, col1, row2, col2)
  349.     int        row1;
  350.     int        col1;
  351.     int        row2;
  352.     int        col2;
  353. {
  354.     if (row1 > row2) return( 1);
  355.     if (row1 < row2) return(-1);
  356.     if (col1 > col2) return( 1);
  357.     if (col1 < col2) return(-1);
  358.              return( 0);
  359. }
  360.  
  361. /*
  362.  * Start out the selection
  363.  */
  364. /* ARGSUSED */
  365.     void
  366. clip_start_selection(button, x, y, repeated_click, modifiers)
  367.     int        button;
  368.     int        x;
  369.     int        y;
  370.     int        repeated_click;
  371.     int_u   modifiers;
  372. {
  373.     VimClipboard    *cb = &clipboard;
  374.  
  375.     if (cb->state == SELECT_DONE)
  376.     clip_clear_selection();
  377.  
  378.     cb->start.lnum  = check_row(Y_2_ROW(y));
  379.     cb->start.col   = check_col(X_2_COL(x));
  380.     cb->end        = cb->start;
  381.     cb->origin_row  = (short_u)cb->start.lnum;
  382.     cb->state        = SELECT_IN_PROGRESS;
  383.  
  384.     if (repeated_click)
  385.     {
  386.     if (++(cb->mode) > SELECT_MODE_LINE)
  387.         cb->mode = SELECT_MODE_CHAR;
  388.     }
  389.     else
  390.     cb->mode = SELECT_MODE_CHAR;
  391.  
  392. #ifdef USE_GUI
  393.     /* clear the cursor until the selection is made */
  394.     gui_undraw_cursor();
  395. #endif
  396.  
  397.     switch (cb->mode)
  398.     {
  399.     case SELECT_MODE_CHAR:
  400.         cb->origin_start_col = cb->start.col;
  401.         cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
  402.         break;
  403.  
  404.     case SELECT_MODE_WORD:
  405.         clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
  406.         cb->origin_start_col = cb->word_start_col;
  407.         cb->origin_end_col     = cb->word_end_col;
  408.  
  409.         clip_invert_area((int)cb->start.lnum, cb->word_start_col,
  410.                 (int)cb->end.lnum, cb->word_end_col);
  411.         cb->start.col = cb->word_start_col;
  412.         cb->end.col   = cb->word_end_col;
  413.         break;
  414.  
  415.     case SELECT_MODE_LINE:
  416.         clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum,
  417.                 (int)Columns);
  418.         cb->start.col = 0;
  419.         cb->end.col   = Columns;
  420.         break;
  421.     }
  422.  
  423.     cb->prev = cb->start;
  424.  
  425. #ifdef DEBUG_SELECTION
  426.     printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col);
  427. #endif
  428. }
  429.  
  430. /*
  431.  * Continue processing the selection
  432.  */
  433. /* ARGSUSED */
  434.     void
  435. clip_process_selection(button, x, y, repeated_click, modifiers)
  436.     int        button;
  437.     int        x;
  438.     int        y;
  439.     int        repeated_click;
  440.     int_u   modifiers;
  441. {
  442.     VimClipboard    *cb = &clipboard;
  443.     int            row;
  444.     int_u        col;
  445.     int            diff;
  446.  
  447.     if (button == MOUSE_RELEASE)
  448.     {
  449.     /* Check to make sure we have something selected */
  450.     if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
  451.     {
  452. #ifdef USE_GUI
  453.         if (gui.in_use)
  454.         gui_update_cursor(FALSE, FALSE);
  455. #endif
  456.         cb->state = SELECT_CLEARED;
  457.         return;
  458.     }
  459.  
  460. #ifdef DEBUG_SELECTION
  461.     printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum,
  462.         cb->start.col, cb->end.lnum, cb->end.col);
  463. #endif
  464.     clip_free_selection();
  465.     clip_own_selection();
  466.     clip_yank_non_visual_selection((int)cb->start.lnum, cb->start.col,
  467.                           (int)cb->end.lnum, cb->end.col);
  468.     clip_mch_set_selection();
  469. #ifdef USE_GUI
  470.     if (gui.in_use)
  471.         gui_update_cursor(FALSE, FALSE);
  472. #endif
  473.  
  474.     cb->state = SELECT_DONE;
  475.     return;
  476.     }
  477.  
  478.     row = check_row(Y_2_ROW(y));
  479.     col = check_col(X_2_COL(x));
  480.  
  481.     if (col == cb->prev.col && row == cb->prev.lnum)
  482.     return;
  483.  
  484.     /*
  485.      * When extending the selection with the right mouse button, swap the
  486.      * start and end if the position is before half the selection
  487.      */
  488.     if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
  489.     {
  490.     /*
  491.      * If the click is before the start, or the click is inside the
  492.      * selection and the start is the closest side, set the origin to the
  493.      * end of the selection.
  494.      */
  495.     if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
  496.         || (clip_compare_pos(row, col,
  497.                        (int)cb->end.lnum, cb->end.col) < 0
  498.             && (((cb->start.lnum == cb->end.lnum
  499.                 && cb->end.col - col > col - cb->start.col))
  500.             || ((diff = (cb->end.lnum - row) -
  501.                            (row - cb->start.lnum)) > 0
  502.                 || (diff == 0 && col < (cb->start.col +
  503.                              cb->end.col) / 2)))))
  504.     {
  505.         cb->origin_row = (short_u)cb->end.lnum;
  506.         cb->origin_start_col = cb->end.col - 1;
  507.         cb->origin_end_col = cb->end.col;
  508.     }
  509.     else
  510.     {
  511.         cb->origin_row = (short_u)cb->start.lnum;
  512.         cb->origin_start_col = cb->start.col;
  513.         cb->origin_end_col = cb->start.col;
  514.     }
  515.     if (cb->mode == SELECT_MODE_WORD)
  516.     {
  517.         clip_get_word_boundaries(cb, cb->origin_row, cb->origin_start_col);
  518.         cb->origin_start_col = cb->word_start_col;
  519.         cb->origin_end_col     = cb->word_end_col;
  520.     }
  521.     }
  522.  
  523.     /* set state, for when using the right mouse button */
  524.     cb->state = SELECT_IN_PROGRESS;
  525.  
  526. #ifdef DEBUG_SELECTION
  527.     printf("Selection extending to (%d,%d)\n", row, col);
  528. #endif
  529.  
  530.     switch (cb->mode)
  531.     {
  532.     case SELECT_MODE_CHAR:
  533.         /* If we're on a different line, find where the line ends */
  534.         if (row != cb->prev.lnum)
  535.         cb->word_end_col = clip_get_line_end(row);
  536.  
  537.         /* See if we are before or after the origin of the selection */
  538.         if (clip_compare_pos(row, col, cb->origin_row,
  539.                            cb->origin_start_col) >= 0)
  540.         {
  541.         if (col >= (int)cb->word_end_col)
  542.             clip_update_non_visual_selection(cb, cb->origin_row,
  543.                 cb->origin_start_col, row, (int)Columns);
  544.         else
  545.             clip_update_non_visual_selection(cb, cb->origin_row,
  546.                 cb->origin_start_col, row, col + 1);
  547.         }
  548.         else
  549.         {
  550.         if (col >= (int)cb->word_end_col)
  551.             clip_update_non_visual_selection(cb, row, cb->word_end_col,
  552.                 cb->origin_row, cb->origin_start_col + 1);
  553.         else
  554.             clip_update_non_visual_selection(cb, row, col,
  555.                 cb->origin_row, cb->origin_start_col + 1);
  556.         }
  557.         break;
  558.  
  559.     case SELECT_MODE_WORD:
  560.         /* If we are still within the same word, do nothing */
  561.         if (row == cb->prev.lnum && col >= (int)cb->word_start_col
  562.             && col < (int)cb->word_end_col)
  563.         return;
  564.  
  565.         /* Get new word boundaries */
  566.         clip_get_word_boundaries(cb, row, col);
  567.  
  568.         /* Handle being after the origin point of selection */
  569.         if (clip_compare_pos(row, col, cb->origin_row,
  570.             cb->origin_start_col) >= 0)
  571.         clip_update_non_visual_selection(cb, cb->origin_row,
  572.             cb->origin_start_col, row, cb->word_end_col);
  573.         else
  574.         clip_update_non_visual_selection(cb, row, cb->word_start_col,
  575.             cb->origin_row, cb->origin_end_col);
  576.         break;
  577.  
  578.     case SELECT_MODE_LINE:
  579.         if (row == cb->prev.lnum)
  580.         return;
  581.  
  582.         if (clip_compare_pos(row, col, cb->origin_row,
  583.             cb->origin_start_col) >= 0)
  584.         clip_update_non_visual_selection(cb, cb->origin_row, 0, row,
  585.             (int)Columns);
  586.         else
  587.         clip_update_non_visual_selection(cb, row, 0, cb->origin_row,
  588.             (int)Columns);
  589.         break;
  590.     }
  591.  
  592.     cb->prev.lnum = row;
  593.     cb->prev.col  = col;
  594.  
  595. #ifdef DEBUG_SELECTION
  596.     printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum,
  597.         cb->start.col, cb->end.lnum, cb->end.col);
  598. #endif
  599. }
  600.  
  601. /*
  602.  * Called after an Expose event to redraw the selection
  603.  */
  604.     void
  605. clip_redraw_selection(x, y, w, h)
  606.     int        x;
  607.     int        y;
  608.     int        w;
  609.     int        h;
  610. {
  611.     VimClipboard    *cb = &clipboard;
  612.     int            row1, col1, row2, col2;
  613.     int            row;
  614.     int            start;
  615.     int            end;
  616.  
  617.     if (cb->state == SELECT_CLEARED)
  618.     return;
  619.  
  620. #ifdef USE_GUI        /* TODO: how do we invert for non-GUI versions? */
  621.     row1 = check_row(Y_2_ROW(y));
  622.     col1 = check_col(X_2_COL(x));
  623.     row2 = check_row(Y_2_ROW(y + h - 1));
  624.     col2 = check_col(X_2_COL(x + w - 1));
  625.  
  626.     /* Limit the rows that need to be re-drawn */
  627.     if (cb->start.lnum > row1)
  628.     row1 = cb->start.lnum;
  629.     if (cb->end.lnum < row2)
  630.     row2 = cb->end.lnum;
  631.  
  632.     /* Look at each row that might need to be re-drawn */
  633.     for (row = row1; row <= row2; row++)
  634.     {
  635.     /* For the first selection row, use the starting selection column */
  636.     if (row == cb->start.lnum)
  637.         start = cb->start.col;
  638.     else
  639.         start = 0;
  640.  
  641.     /* For the last selection row, use the ending selection column */
  642.     if (row == cb->end.lnum)
  643.         end = cb->end.col;
  644.     else
  645.         end = Columns;
  646.  
  647.     if (col1 > start)
  648.         start = col1;
  649.  
  650.     if (col2 < end)
  651.         end = col2 + 1;
  652.  
  653.     if (end > start)
  654.         gui_mch_invert_rectangle(row, start, 1, end - start);
  655.     }
  656. #endif
  657. }
  658.  
  659. /*
  660.  * Redraw the selection if character at "row,col" is inside of it.
  661.  */
  662.     void
  663. clip_may_redraw_selection(row, col)
  664.     int    row, col;
  665. {
  666.     if (clipboard.state != SELECT_CLEARED
  667.         && ((row == clipboard.start.lnum
  668.             && col >= (int)clipboard.start.col)
  669.         || row > clipboard.start.lnum)
  670.         && ((row == clipboard.end.lnum
  671.             && col < (int)clipboard.end.col)
  672.         || row < clipboard.end.lnum))
  673.     clip_invert_area(row, col, row, col + 1);
  674. }
  675.  
  676. /*
  677.  * Called from outside to clear selected region from the display
  678.  */
  679.     void
  680. clip_clear_selection()
  681. {
  682.     VimClipboard    *cb = &clipboard;
  683.  
  684.     if (cb->state == SELECT_CLEARED)
  685.     return;
  686.  
  687.     clip_invert_area((int)cb->start.lnum, cb->start.col, (int)cb->end.lnum,
  688.         cb->end.col);
  689.     cb->state = SELECT_CLEARED;
  690. }
  691.  
  692. /*
  693.  * Clear the selection if any lines from "row1" to "row2" are inside of it.
  694.  */
  695.     void
  696. clip_may_clear_selection(row1, row2)
  697.     int    row1, row2;
  698. {
  699.     if (clipboard.state == SELECT_DONE
  700.         && row2 >= clipboard.start.lnum
  701.         && row1 <= clipboard.end.lnum)
  702.     clip_clear_selection();
  703. }
  704.  
  705. /*
  706.  * Called before the screen is scrolled up or down.  Adjusts the line numbers
  707.  * of the selection.  Call with big number when clearing the screen.
  708.  */
  709.     void
  710. clip_scroll_selection(rows)
  711.     int        rows;        /* negative for scroll down */
  712. {
  713.     int        lnum;
  714.  
  715.     if (clipboard.state == SELECT_CLEARED)
  716.     return;
  717.  
  718.     lnum = clipboard.start.lnum - rows;
  719.     if (lnum <= 0)
  720.     clipboard.start.lnum = 0;
  721.     else if (lnum >= screen_Rows)    /* scrolled off of the screen */
  722.     clipboard.state = SELECT_CLEARED;
  723.     else
  724.     clipboard.start.lnum = lnum;
  725.  
  726.     lnum = clipboard.end.lnum - rows;
  727.     if (lnum < 0)            /* scrolled off of the screen */
  728.     clipboard.state = SELECT_CLEARED;
  729.     else if (lnum >= screen_Rows)
  730.     clipboard.end.lnum = screen_Rows - 1;
  731.     else
  732.     clipboard.end.lnum = lnum;
  733. }
  734.  
  735. /*
  736.  * Invert a region of the display between a starting and ending row and column
  737.  */
  738.     static void
  739. clip_invert_area(row1, col1, row2, col2)
  740.     int        row1;
  741.     int        col1;
  742.     int        row2;
  743.     int        col2;
  744. {
  745. #ifdef USE_GUI        /* TODO: how do we invert for non-GUI versions? */
  746.     /* Swap the from and to positions so the from is always before */
  747.     if (clip_compare_pos(row1, col1, row2, col2) > 0)
  748.     {
  749.     int tmp_row, tmp_col;
  750.     tmp_row = row1;
  751.     tmp_col = col1;
  752.     row1    = row2;
  753.     col1    = col2;
  754.     row2    = tmp_row;
  755.     col2    = tmp_col;
  756.     }
  757.  
  758.     /* If all on the same line, do it the easy way */
  759.     if (row1 == row2)
  760.     {
  761.     gui_mch_invert_rectangle(row1, col1, 1, col2 - col1);
  762.     return;
  763.     }
  764.  
  765.     /* Handle a piece of the first line */
  766.     if (col1 > 0)
  767.     {
  768.     gui_mch_invert_rectangle(row1, col1, 1, (int)Columns - col1);
  769.     row1++;
  770.     }
  771.  
  772.     /* Handle a piece of the last line */
  773.     if (col2 < Columns - 1)
  774.     {
  775.     gui_mch_invert_rectangle(row2, 0, 1, col2);
  776.     row2--;
  777.     }
  778.  
  779.     /* Handle the rectangle thats left */
  780.     if (row2 >= row1)
  781.     gui_mch_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns);
  782. #endif
  783. }
  784.  
  785. /*
  786.  * Yank the currently selected area into the special selection buffer so it
  787.  * will be available for pasting.
  788.  */
  789.     static void
  790. clip_yank_non_visual_selection(row1, col1, row2, col2)
  791.     int        row1;
  792.     int        col1;
  793.     int        row2;
  794.     int        col2;
  795. {
  796.     char_u  *buffer;
  797.     char_u  *bufp;
  798.     int        row;
  799.     int        start_col;
  800.     int        end_col;
  801.     int        line_end_col;
  802.     int        add_newline_flag = FALSE;
  803.  
  804.     /*
  805.      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
  806.      */
  807.     if (row1 > row2)
  808.     {
  809.     row = row1; row1 = row2; row2 = row;
  810.     row = col1; col1 = col2; col2 = row;
  811.     }
  812.     else if (row1 == row2 && col1 > col2)
  813.     {
  814.     row = col1; col1 = col2; col2 = row;
  815.     }
  816.  
  817.     /* Create a temporary buffer for storing the text */
  818.     buffer = lalloc((row2 - row1 + 1) * Columns + 1, TRUE);
  819.     if (buffer == NULL)        /* out of memory */
  820.     return;
  821.  
  822.     /* Process each row in the selection */
  823.     for (bufp = buffer, row = row1; row <= row2; row++)
  824.     {
  825.     if (row == row1)
  826.         start_col = col1;
  827.     else
  828.         start_col = 0;
  829.  
  830.     if (row == row2)
  831.         end_col = col2;
  832.     else
  833.         end_col = Columns;
  834.  
  835.     line_end_col = clip_get_line_end(row);
  836.  
  837.     /* See if we need to nuke some trailing whitespace */
  838.     if (end_col >= Columns && (row < row2 || end_col > line_end_col))
  839.     {
  840.         /* Get rid of trailing whitespace */
  841.         end_col = line_end_col;
  842.         if (end_col < start_col)
  843.         end_col = start_col;
  844.  
  845.         /* If the last line extended to the end, add an extra newline */
  846.         if (row == row2)
  847.         add_newline_flag = TRUE;
  848.     }
  849.  
  850.     /* If after the first row, we need to always add a newline */
  851.     if (row > row1)
  852.         *bufp++ = NL;
  853.  
  854.     if (row < screen_Rows && end_col <= screen_Columns)
  855.     {
  856.         STRNCPY(bufp, &LinePointers[row][start_col], end_col - start_col);
  857.         bufp += end_col - start_col;
  858.     }
  859.     }
  860.  
  861.     /* Add a newline at the end if the selection ended there */
  862.     if (add_newline_flag)
  863.     *bufp++ = NL;
  864.  
  865.     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer));
  866.     vim_free(buffer);
  867. }
  868.  
  869. /*
  870.  * Find the starting and ending positions of the word at the given row and
  871.  * column.
  872.  */
  873.     static void
  874. clip_get_word_boundaries(cb, row, col)
  875.     VimClipboard    *cb;
  876.     int            row;
  877.     int            col;
  878. {
  879.     char    start_class;
  880.     int        temp_col;
  881.  
  882.     if (row >= screen_Rows || col >= screen_Columns)
  883.     return;
  884.  
  885.     start_class = char_class(LinePointers[row][col]);
  886.  
  887.     temp_col = col;
  888.     for ( ; temp_col > 0; temp_col--)
  889.     if (char_class(LinePointers[row][temp_col - 1]) != start_class)
  890.         break;
  891.  
  892.     cb->word_start_col = temp_col;
  893.  
  894.     temp_col = col;
  895.     for ( ; temp_col < screen_Columns; temp_col++)
  896.     if (char_class(LinePointers[row][temp_col]) != start_class)
  897.         break;
  898.     cb->word_end_col = temp_col;
  899.  
  900. #ifdef DEBUG_SELECTION
  901.     printf("Current word: col %u to %u\n", cb->word_start_col,
  902.         cb->word_end_col);
  903. #endif
  904. }
  905.  
  906. /*
  907.  * Find the column position for the last non-whitespace character on the given
  908.  * line.
  909.  */
  910.     static int
  911. clip_get_line_end(row)
  912.     int        row;
  913. {
  914.     int        i;
  915.  
  916.     if (row >= screen_Rows)
  917.     return 0;
  918.     for (i = screen_Columns; i > 0; i--)
  919.     if (LinePointers[row][i - 1] != ' ')
  920.         break;
  921.     return i;
  922. }
  923.  
  924. /*
  925.  * Update the currently selected region by adding and/or subtracting from the
  926.  * beginning or end and inverting the changed area(s).
  927.  */
  928.     static void
  929. clip_update_non_visual_selection(cb, row1, col1, row2, col2)
  930.     VimClipboard    *cb;
  931.     int            row1;
  932.     int            col1;
  933.     int            row2;
  934.     int            col2;
  935. {
  936.     /* See if we changed at the beginning of the selection */
  937.     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
  938.     {
  939.     clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col);
  940.     cb->start.lnum = row1;
  941.     cb->start.col  = col1;
  942.     }
  943.  
  944.     /* See if we changed at the end of the selection */
  945.     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
  946.     {
  947.     clip_invert_area(row2, col2, (int)cb->end.lnum, cb->end.col);
  948.     cb->end.lnum = row2;
  949.     cb->end.col  = col2;
  950.     }
  951. }
  952.  
  953. #else /* If USE_GUI not defined */
  954.  
  955. /*
  956.  * Called from outside to clear selected region from the display
  957.  */
  958.     void
  959. clip_clear_selection()
  960. {
  961.     /*
  962.      * Dummy version for now... the point of this code is to set the selected
  963.      * area back to "normal" colour if we are clearing the selection. As we
  964.      * don't have GUI-style mouse selection, we can ignore this for now.
  965.      * Eventually we could actually invert the area in a terminal by redrawing
  966.      * in reverse mode, but we don't do that yet.
  967.      */
  968.     clipboard.state = SELECT_CLEARED;
  969. }
  970. #endif /* USE_GUI */
  971.  
  972.  
  973. #endif /* USE_CLIPBOARD */
  974.  
  975. /*****************************************************************************
  976.  * Functions that handle the input buffer.
  977.  * This is used for any GUI version, and the unix terminal version.
  978.  *
  979.  * For Unix, the input characters are buffered to be able to check for a
  980.  * CTRL-C.  This should be done with signals, but I don't know how to do that
  981.  * in a portable way for a tty in RAW mode.
  982.  */
  983.  
  984. #if defined(UNIX) || defined(USE_GUI) || defined(OS2)
  985.  
  986. /*
  987.  * Internal typeahead buffer.  Includes extra space for long key code
  988.  * descriptions which would otherwise overflow.  The buffer is considered full
  989.  * when only this extra space (or part of it) remains.
  990.  */
  991. #define INBUFLEN 250
  992.  
  993. static char_u    inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
  994. static int    inbufcount = 0;        /* number of chars in inbuf[] */
  995.  
  996. /*
  997.  * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
  998.  * trash_input_buf() are functions for manipulating the input buffer.  These
  999.  * are used by the gui_* calls when a GUI is used to handle keyboard input.
  1000.  */
  1001.  
  1002.     int
  1003. vim_is_input_buf_full()
  1004. {
  1005.     return (inbufcount >= INBUFLEN);
  1006. }
  1007.  
  1008.     int
  1009. vim_is_input_buf_empty()
  1010. {
  1011.     return (inbufcount == 0);
  1012. }
  1013.  
  1014.     int
  1015. vim_free_in_input_buf()
  1016. {
  1017.     return (INBUFLEN - inbufcount);
  1018. }
  1019.  
  1020. /* Add the given bytes to the input buffer */
  1021.     void
  1022. add_to_input_buf(s, len)
  1023.     char_u  *s;
  1024.     int        len;
  1025. {
  1026.     if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
  1027.     return;        /* Shouldn't ever happen! */
  1028.  
  1029.     while (len--)
  1030.     inbuf[inbufcount++] = *s++;
  1031. }
  1032.  
  1033. /* Remove everything from the input buffer.  Called when ^C is found */
  1034.     void
  1035. trash_input_buf()
  1036. {
  1037.     inbufcount = 0;
  1038. }
  1039.  
  1040. /*
  1041.  * Read as much data from the input buffer as possible up to maxlen, and store
  1042.  * it in buf.
  1043.  * Note: this function used to be Read() in unix.c
  1044.  */
  1045.     int
  1046. read_from_input_buf(buf, maxlen)
  1047.     char_u  *buf;
  1048.     long    maxlen;
  1049. {
  1050.     if (inbufcount == 0)    /* if the buffer is empty, fill it */
  1051.     fill_input_buf(TRUE);
  1052.     if (maxlen > inbufcount)
  1053.     maxlen = inbufcount;
  1054.     vim_memmove(buf, inbuf, (size_t)maxlen);
  1055.     inbufcount -= maxlen;
  1056.     if (inbufcount)
  1057.     vim_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
  1058.     return (int)maxlen;
  1059. }
  1060.  
  1061.     void
  1062. fill_input_buf(exit_on_error)
  1063.     int    exit_on_error;
  1064. {
  1065. #if defined(UNIX) || defined(OS2)
  1066.     int        len;
  1067.     int        try;
  1068.     static int    did_read_something = FALSE;
  1069. #endif
  1070.  
  1071. #ifdef USE_GUI
  1072.     if (gui.in_use)
  1073.     {
  1074.     gui_mch_update();
  1075.     return;
  1076.     }
  1077. #endif
  1078. #if defined(UNIX) || defined(OS2)
  1079.     if (vim_is_input_buf_full())
  1080.     return;
  1081.     /*
  1082.      * Fill_input_buf() is only called when we really need a character.
  1083.      * If we can't get any, but there is some in the buffer, just return.
  1084.      * If we can't get any, and there isn't any in the buffer, we give up and
  1085.      * exit Vim.
  1086.      */
  1087. # ifdef __BEOS__
  1088.     /*
  1089.      * On the BeBox version (for now), all input is secretly performed within
  1090.      * beos_select() which is called from RealWaitForChar().
  1091.      */
  1092.     while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0))
  1093.         ;
  1094.     len = inbufcount;
  1095.     inbufcount = 0;
  1096. # else
  1097.  
  1098. #ifdef USE_SNIFF
  1099.     if (sniff_request_waiting)
  1100.     {
  1101.     add_to_input_buf((char_u *)"\233sniff",6); /* results in K_SNIFF */
  1102.     sniff_request_waiting = 0;
  1103.     want_sniff_request = 0;
  1104.     return;
  1105.     }
  1106. #endif
  1107.  
  1108.     for (try = 0; try < 100; ++try)
  1109.     {
  1110.     len = read(read_cmd_fd, (char *)inbuf + inbufcount,
  1111.                          (size_t)(INBUFLEN - inbufcount));
  1112.     if (len > 0 || got_int)
  1113.         break;
  1114.     /*
  1115.      * If reading stdin results in an error, continue reading stderr.
  1116.      * This helps when using "foo | xargs vim".
  1117.      */
  1118.     if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
  1119.         read_cmd_fd = 2;
  1120.     if (!exit_on_error)
  1121.         return;
  1122.     }
  1123. # endif
  1124.     if (len <= 0 && !got_int)
  1125.     read_error_exit();
  1126.     did_read_something = TRUE;
  1127.     if (got_int)
  1128.     {
  1129.     inbuf[inbufcount] = 3;
  1130.     inbufcount = 1;
  1131.     }
  1132.     else
  1133.     while (len-- > 0)
  1134.     {
  1135.         /*
  1136.          * if a CTRL-C was typed, remove it from the buffer and set got_int
  1137.          */
  1138.         if (inbuf[inbufcount] == 3)
  1139.         {
  1140.         /* remove everything typed before the CTRL-C */
  1141.         vim_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
  1142.         inbufcount = 0;
  1143.         got_int = TRUE;
  1144.         }
  1145.         ++inbufcount;
  1146.     }
  1147. #endif /* UNIX or OS2 */
  1148. }
  1149. #endif /* defined(UNIX) || defined(USE_GUI) || defined(OS2) */
  1150.  
  1151. /*
  1152.  * Exit because of an input read error.
  1153.  */
  1154.     void
  1155. read_error_exit()
  1156. {
  1157.     if (silent_mode)    /* Normal way to exit for "ex -s" */
  1158.     getout(0);
  1159.     STRCPY(IObuff, "Vim: Error reading input, exiting...\n");
  1160.     preserve_exit();
  1161. }
  1162.